using Microsoft.Extensions.Options;
using RabbitMQ.Client;
using RabbitMQ.Client.Exceptions;
using System.Text;
using WebRtcProject.Models.Configuration;
using WebRtcProject.Models.Messages;
using RabbitMQ.Client.Events;
using System.Text.Json;

namespace WebRtcProject.Services
{
    /// <summary>
    /// RabbitMQ 外部服务连接器
    /// 专注于连接现有 RabbitMQ 服务器，实现队列订阅和消息发送功能
    /// </summary>
    public class RabbitMQService : IRabbitMQService, IDisposable
    {
        private readonly ILogger<RabbitMQService> _logger;
        private readonly RabbitMQOptions _options;
        private IConnection? _connection;
        private IModel? _channel;
        private readonly object _lockObject = new();
        private bool _disposed = false;

        public RabbitMQService(ILogger<RabbitMQService> logger, IOptions<RabbitMQOptions> options)
        {
            _logger = logger;
            _options = options.Value;
        }

        /// <summary>
        /// 初始化连接到外部 RabbitMQ 服务器
        /// </summary>
        public async Task InitializeAsync()
        {
            if (!_options.Enabled)
            {
                _logger.LogInformation("RabbitMQ 服务已禁用");
                return;
            }

            try
            {
                await ConnectAsync();
                _logger.LogInformation("RabbitMQ 外部服务连接成功 - 服务器: {HostName}:{Port}", 
                    _options.HostName, _options.Port);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "连接到 RabbitMQ 外部服务失败");
                throw;
            }
        }

        /// <summary>
        /// 连接到 RabbitMQ 服务器
        /// </summary>
        private async Task ConnectAsync()
        {
            var factory = new ConnectionFactory
            {
                HostName = _options.HostName,
                Port = _options.Port,
                UserName = _options.UserName,
                Password = _options.Password,
                VirtualHost = _options.VirtualHost,
                RequestedConnectionTimeout = _options.ConnectionTimeout,
                RequestedHeartbeat = _options.HeartbeatInterval,
                AutomaticRecoveryEnabled = true,
                NetworkRecoveryInterval = TimeSpan.FromSeconds(10)
            };

            // 配置 TLS
            if (_options.UseTLS)
            {
                factory.Ssl = new SslOption
                {
                    Enabled = true,
                    ServerName = _options.HostName,
                    AcceptablePolicyErrors = System.Net.Security.SslPolicyErrors.RemoteCertificateNameMismatch |
                                           System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors
                };
            }

            lock (_lockObject)
            {
                _connection = factory.CreateConnection();
                _channel = _connection.CreateModel();

                // 配置通道
                if (_options.Publishing.ConfirmMode)
                {
                    _channel.ConfirmSelect();
                }

                // 设置 QoS
                _channel.BasicQos(0, _options.Subscription.PrefetchCount, false);
            }

            _logger.LogInformation("RabbitMQ 连接建立成功");
        }

        /// <summary>
        /// 订阅指定队列的消息
        /// </summary>
        /// <param name="queueName">队列名称</param>
        /// <param name="messageHandler">消息处理器</param>
        /// <param name="cancellationToken">取消令牌</param>
        public async Task SubscribeToQueueAsync(string queueName, 
            Func<string, Task<bool>> messageHandler, 
            CancellationToken cancellationToken = default)
        {
            if (_channel == null)
            {
                throw new InvalidOperationException("RabbitMQ 连接未初始化");
            }

            //声明队列：名称、持久、非私有，默认不删。参数：队列优先级。
            _channel.QueueDeclare(queueName, durable: true, exclusive: false, autoDelete: true,
                arguments: new Dictionary<string, object> { { "x-max-priority", 10 } });

            //队列根据路由键绑上交换机: 设bindKey = routeKey（非通配模式）
            _channel.QueueBind(queueName, RabbitMQOptions.ExchangeName, "Client.#");


            //消费能力：预读消息上限（0无限）、有效载荷字节数（0无限）、信道单一消费独享
            _channel.BasicQos(prefetchCount: 0, prefetchSize: 0, global: false);


            var consumer = new EventingBasicConsumer(_channel);
            
            consumer.Received += async (model, ea) =>
            {
                var message = Encoding.UTF8.GetString(ea.Body.ToArray());
                var deliveryTag = ea.DeliveryTag;
                var retryCount = GetRetryCount(ea.BasicProperties);

                try
                {
                    _logger.LogDebug("收到消息从队列 {QueueName}: {Message}", queueName, message);
                    
                    var success = await messageHandler(message);
                    
                    if (success)
                    {
                        // 手动确认消息
                        if (!_options.Subscription.AutoAck)
                        {
                            _channel.BasicAck(deliveryTag, false);
                        }
                        _logger.LogDebug("消息处理成功: {DeliveryTag}", deliveryTag);
                    }
                    else
                    {
                        await HandleMessageFailure(queueName, message, deliveryTag, retryCount);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "处理消息时发生错误: {Message}", message);
                    await HandleMessageFailure(queueName, message, deliveryTag, retryCount);
                }
            };

            // 开始消费
            _channel.BasicConsume(queue: queueName,
                                autoAck: _options.Subscription.AutoAck,
                                consumer: consumer);

            _logger.LogInformation("开始订阅队列: {QueueName}", queueName);

            // 等待取消令牌
            await Task.Delay(Timeout.Infinite, cancellationToken);
        }

        /// <summary>
        /// 发送消息到指定队列
        /// </summary>
        /// <param name="queueName">队列名称</param>
        /// <param name="message">消息内容</param>
        /// <param name="routingKey">路由键（可选）</param>
        public async Task PublishMessageAsync(string queueName, object message, string? routingKey = null)
        {
            if (_channel == null)
            {
                throw new InvalidOperationException("RabbitMQ 连接未初始化");
            }

            try
            {
                var json = JsonSerializer.Serialize(message);
                var body = Encoding.UTF8.GetBytes(json);

                var properties = _channel.CreateBasicProperties();
                properties.Persistent = _options.Publishing.Persistent;
                properties.MessageId = Guid.NewGuid().ToString();
                properties.Timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeSeconds());

                // 直接发送到队列
                _channel.BasicPublish(exchange: RabbitMQOptions.ExchangeName,
                                    routingKey: routingKey ?? queueName,
                                    mandatory: _options.Publishing.Mandatory,
                                    basicProperties: properties,
                                    body: body);

                // 等待确认（如果启用）
                if (_options.Publishing.ConfirmMode)
                {
                    _channel.WaitForConfirms(TimeSpan.FromSeconds(10));
                }

                _logger.LogDebug("消息发送成功到队列 {QueueName}: {MessageId}", queueName, properties.MessageId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发送消息到队列 {QueueName} 失败", queueName);
                throw;
            }
        }

        /// <summary>
        /// 发送WebRTC事件消息
        /// </summary>
        public async Task PublishWebRtcEventAsync(object eventData)
        {
            await PublishMessageAsync(_options.TargetQueues.OutgoingQueue, eventData);
        }

        /// <summary>
        /// 发送通知消息
        /// </summary>
        public async Task PublishNotificationAsync(object notification)
        {
            await PublishMessageAsync(_options.TargetQueues.NotificationQueue, notification);
        }

        /// <summary>
        /// 订阅传入消息队列
        /// </summary>
        public async Task SubscribeToIncomingMessagesAsync(
            Func<string, Task<bool>> messageHandler,
            CancellationToken cancellationToken = default)
        {
            await SubscribeToQueueAsync(_options.TargetQueues.IncomingQueue, messageHandler, cancellationToken);
        }

        /// <summary>
        /// 处理消息失败
        /// </summary>
        private async Task HandleMessageFailure(string queueName, string message, ulong deliveryTag, int retryCount)
        {
            retryCount++;

            if (retryCount <= _options.Subscription.MaxRetryAttempts && _options.Subscription.RequeueOnFailure)
            {
                // 重新入队
                _channel?.BasicNack(deliveryTag, false, true);
                _logger.LogWarning("消息重新入队 (重试 {RetryCount}/{MaxRetries}): {Message}", 
                    retryCount, _options.Subscription.MaxRetryAttempts, message);
            }
            else
            {
                // 拒绝消息，不重新入队
                _channel?.BasicNack(deliveryTag, false, false);
                _logger.LogError("消息处理失败，已丢弃 (重试次数已达上限): {Message}", message);
            }
        }

        /// <summary>
        /// 获取消息重试次数
        /// </summary>
        private int GetRetryCount(IBasicProperties? properties)
        {
            if (properties?.Headers != null && 
                properties.Headers.TryGetValue("x-retry-count", out var retryCountObj))
            {
                return Convert.ToInt32(retryCountObj);
            }
            return 0;
        }

        /// <summary>
        /// 检查连接状态
        /// </summary>
        public bool IsConnected => _connection?.IsOpen == true && _channel?.IsOpen == true;

        /// <summary>
        /// 获取连接状态信息
        /// </summary>
        public object GetConnectionStatus()
        {
            return new
            {
                IsConnected = IsConnected,
                HostName = _options.HostName,
                Port = _options.Port,
                VirtualHost = _options.VirtualHost,
                TargetQueues = new
                {
                    Incoming = _options.TargetQueues.IncomingQueue,
                    Outgoing = _options.TargetQueues.OutgoingQueue,
                    Notification = _options.TargetQueues.NotificationQueue
                }
            };
        }

        public void Dispose()
        {
            if (_disposed) return;

            try
            {
                _channel?.Close();
                _channel?.Dispose();
                _connection?.Close();
                _connection?.Dispose();
                
                _logger.LogInformation("RabbitMQ 连接已关闭");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "关闭 RabbitMQ 连接时发生错误");
            }
            finally
            {
                _disposed = true;
            }
        }

        // =========================
        // IRabbitMQService 接口实现
        // =========================

        public async Task PublishAsync<T>(T message, string exchangeName, string routingKey = "") where T : BaseMessage
        {
            if (_channel == null)
            {
                throw new InvalidOperationException("RabbitMQ 连接未初始化");
            }

            try
            {
                var json = JsonSerializer.Serialize(message);
                var body = Encoding.UTF8.GetBytes(json);

                var properties = _channel.CreateBasicProperties();
                properties.Persistent = _options.Publishing.Persistent;
                properties.MessageId = Guid.NewGuid().ToString();
                properties.Timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeSeconds());

                _channel.BasicPublish(exchange: exchangeName,
                                     routingKey: routingKey,
                                     basicProperties: properties,
                                     body: body);

                _logger.LogDebug("消息已发布到交换机 {ExchangeName} 路由键 {RoutingKey}", exchangeName, routingKey);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发布消息失败到交换机 {ExchangeName}", exchangeName);
                throw;
            }
        }

        public async Task PublishUserEventAsync(UserEventMessage message)
        {
            await PublishAsync(message, RabbitMQOptions.ExchangeName, "user.event");
        }

        public async Task PublishRoomEventAsync(RoomEventMessage message)
        {
            await PublishAsync(message, RabbitMQOptions.ExchangeName, "room.event");
        }

        public async Task PublishSignalingEventAsync(SignalingEventMessage message)
        {
            await PublishAsync(message, RabbitMQOptions.ExchangeName, "signaling.event");
        }

        public async Task<bool> IsConnectedAsync()
        {
            return IsConnected;
        }

        public async Task ReconnectAsync()
        {
            try
            {
                Dispose();
                await ConnectAsync();
                _logger.LogInformation("RabbitMQ 重新连接成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "RabbitMQ 重新连接失败");
                throw;
            }
        }

        public async Task<bool> HealthCheckAsync()
        {
            try
            {
                return IsConnected && _channel?.IsOpen == true;
            }
            catch
            {
                return false;
            }
        }
    }
} 